package com.potevio.simulator.heart;


import com.potevio.simulator.decode.MsgDecoder;
import com.potevio.simulator.encode.MsgEncode;
import com.potevio.simulator.handle.EchoClientHandle;
import com.potevio.simulator.task.CommonTask;
import com.potevio.simulator.task.SiginMsgTask;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.ScheduledFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 客户端启动类
 * @Date 2021/6/1  9:42
 * @author zyd
 * @Version 1.0
 */
@Component
public class HeartbeatClient {
    private final static Logger LOGGER = LoggerFactory.getLogger(HeartbeatClient.class);
    private NioEventLoopGroup worker = new NioEventLoopGroup();
    public static Channel channel;
    private Bootstrap bootstrap;

    /**
     * netty端口
     */
    public static int nettyPort;

    /**
     * nettyIP
     */
    public static String host;

    /**
     * netty异步操作的结果
     */
    private static ChannelFuture connect;

    /**
     * 充电过程报文定时任务Future
     */
    public static ScheduledFuture chargeMsgTaskFuture;

    /**
     * 充电桩状态（0-启动；1-充电中）
     */
    public static int chargingPileState = 0;

    public static Map<String, ScheduledFuture> chargeMsgTaskFutureMaps = new HashMap<>();

    /**
     * 心跳时间间隔
     */
    public static int heartBeatInterval;

    /**
     * 签到时间间隔
     */
    public static int siginInterval;

    /**
     * 充电报文间隔
     */
    public static int chargeMsgInterval;

    /**
     * 充电过程报文定时任务类名
     */
    public static String chargeMsgTaskClass;

    /**
     * 充电过程报文定时任务方法集合
     */
    public static String chargeMsgTaskMethods;
    /**
     * 充电枪数量
     */
    public static String chargeGunNum;

    /**
     * 定额充电电量
     */
    public static int ratedCharge;

    /**
     * 充电类型（0-扫码；1-刷卡）
     */
    public static String chargeType;

    @Value("${netty.client.port}")
    public void setNettyPort(int nettyPort) {
        HeartbeatClient.nettyPort = nettyPort;
    }

    @Value("${netty.client.host}")
    public void setHost(String host) {
        HeartbeatClient.host = host;
    }

    @Value("${netty.client.heart-beat-interval}")
    public void setHeartBeatTime(int heartBeatInterval) {
        HeartbeatClient.heartBeatInterval = heartBeatInterval;
    }

    @Value("${netty.client.sigin-interval}")
    public void setsiginInterval(int siginInterval) {
        HeartbeatClient.siginInterval = siginInterval;
    }

    @Value("${netty.client.charge-msg-interval}")
    public void setChargeMsgInterval(int chargeMsgInterval) {
        HeartbeatClient.chargeMsgInterval = chargeMsgInterval;
    }

    @Value("${netty.client.charge-msg-task-class}")
    public void setChargeMsgTaskClass(String chargeMsgTaskClass) {
        HeartbeatClient.chargeMsgTaskClass = chargeMsgTaskClass;
    }

    @Value("${netty.client.charge-msg-task-methods}")
    public void setChargeMsgTaskMethods(String chargeMsgTaskMethods) {
        HeartbeatClient.chargeMsgTaskMethods = chargeMsgTaskMethods;
    }

    @Value("${netty.client.rated-charge}")
    public void setRatedCharge(int ratedCharge) {
        HeartbeatClient.ratedCharge = ratedCharge;

    }

    @Value("${netty.client.charge-gun-num}")
    public void setChargeTypes(String chargeGunNum) {
        HeartbeatClient.chargeGunNum = chargeGunNum;
    }
    /**
     * 启动netty客户端
     *
     * @throws InterruptedException
     */
    public String start() throws InterruptedException {
        bootstrap = new Bootstrap();
        bootstrap.group(worker)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        // TODO Auto-generated method stub
                        ChannelPipeline pipeline = ch.pipeline();
                        // IdleStateHandler（
                        // readerIdleTimeSeconds：读空闲时间（客户端一定时间内未接收到服务端消息）
                        // writerIdleTimeSeconds：写空闲时间（客户端一定时间内未向服务端发送消息）
                        // allIdleTimeSeconds：所有类型的超时时间
                        pipeline.addLast(new IdleStateHandler(0, heartBeatInterval, 0));
                        System.out.println("添加处理器handler");
                        pipeline.addLast(new MsgEncode());
                        pipeline.addLast(new MsgDecoder());
                        pipeline.addLast(new EchoClientHandle(HeartbeatClient.this));
                    }
                });
        return doConnect();
    }

    /**
     * 连接服务端 and 重连
     */
    public String doConnect() throws InterruptedException {

        if (channel != null && channel.isActive()) {
            return "";
        }
        connect = bootstrap.connect(host, nettyPort).sync();
        // 通过实现监听通道连接的方法实现重连
        connect.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                // 判断连接是否成功
                if (channelFuture.isSuccess()) {
                    channel = channelFuture.channel();
                    SiginMsgTask.LAST_START_TIME = new Date();
                    LOGGER.info("启动 Netty 成功");
                    // 开启充电报文定时任务
                    new CommonTask().startChargeMsgTask(channel);
                } else {
                    LOGGER.info("每隔2s重连....");
                    // 开启线程执行重连
                    channelFuture.channel().eventLoop().schedule(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                doConnect();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }, 2, TimeUnit.SECONDS);
                }
            }
        });
        return "模拟器启动成功";
    }

    /**
     * 关闭连接
     *
     * @throws InterruptedException
     */
    public void closeConnect() throws InterruptedException {
        ChannelFuture channelFuture = connect.channel().close();
        channelFuture.sync();
    }
}